package pers.xiaojun.boot.module.infra.service.file;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import pers.xiaojun.boot.common.constants.DateTimePatternConstants;
import pers.xiaojun.boot.common.exception.BusinessException;
import pers.xiaojun.boot.file.core.client.FileClient;
import pers.xiaojun.boot.file.core.client.FileClientFactory;
import pers.xiaojun.boot.file.core.enums.FileStorageEnum;
import pers.xiaojun.boot.module.infra.constants.FileConfigConstants;
import pers.xiaojun.boot.module.infra.controller.file.vo.config.FileConfigQueryReqVO;
import pers.xiaojun.boot.module.infra.controller.file.vo.config.FileConfigSaveReqVO;
import pers.xiaojun.boot.module.infra.convert.file.FileConfigConvert;
import pers.xiaojun.boot.module.infra.dao.entity.FileConfigDO;
import pers.xiaojun.boot.module.infra.dao.mapper.FileConfigMapper;
import pers.xiaojun.boot.mybatis.core.convert.PageConvert;
import pers.xiaojun.boot.mybatis.core.query.LambdaQueryWrapperX;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import static pers.xiaojun.boot.module.infra.constants.BusinessCodeConstants.*;

/**
 * 文件配置服务层实现
 *
 * @author xiaojun
 * @since 2025-11-13
 */
@Service
@RequiredArgsConstructor
public class FileConfigServiceImpl extends ServiceImpl<FileConfigMapper, FileConfigDO> implements FileConfigService {

    private final FileClientFactory fileClientFactory;

    @Override
    @SneakyThrows
    public FileConfigDO saveFileConfig(FileConfigSaveReqVO saveVO) {
        // 校验基础信息
        validateFileConfigBasicInfo(null, saveVO.getName(), saveVO.getStorage());

        FileConfigDO config = FileConfigConvert.INSTANCE.toFileConfigDO(saveVO);
        config.setMaster(false);
        this.baseMapper.insert(config);

        return config;
    }

    @Override
    public FileConfigDO updateFileConfig(FileConfigSaveReqVO updateVO) {
        // 校验是否存在
        validateFileConfigExists(updateVO.getId());
        // 校验基础信息
        validateFileConfigBasicInfo(updateVO.getId(), updateVO.getName(), updateVO.getStorage());
        // 更新配置
        FileConfigDO config = FileConfigConvert.INSTANCE.toFileConfigDO(updateVO);
        this.baseMapper.updateById(config);

        return config;
    }

    @Override
    public void updateFileConfigAsMaster(Long id) {
        FileConfigDO config = validateFileConfigExists(id);
        // 校验是否已经是主配置
        if (config.getMaster()) {
            throw new BusinessException(FILE_CONFIG_ALREADY_MASTER);
        }

        // 取消当前主配置
        this.baseMapper.updateMasterToFalse();
        // 设置新的主配置
        this.baseMapper.updateMasterById(id, true);
    }

    @Override
    public void removeFileConfigById(Long id) {
        FileConfigDO config = validateFileConfigExists(id);
        // 主配置无法删除
        if (config.getMaster()) {
            throw new BusinessException(FILE_CONFIG_MASTER_CANNOT_BE_DELETED);
        }
        this.baseMapper.deleteById(id);
    }

    @Override
    public FileConfigDO getFileConfigById(Long id) {
        return validateFileConfigExists(id);
    }

    @Override
    public FileConfigDO getMaterFileConfig() {
        return this.baseMapper.selectOne(new LambdaQueryWrapper<FileConfigDO>()
                .eq(FileConfigDO::getMaster, FileConfigConstants.MASTER_MARK)
        );
    }

    @Override
    public Page<FileConfigDO> listFileConfigsPage(FileConfigQueryReqVO queryVO) {
        return this.baseMapper.selectPage(PageConvert.INSTANCE.toPage(queryVO), new LambdaQueryWrapperX<FileConfigDO>()
                .likeIfPresent(FileConfigDO::getName, queryVO.getName())
                .eqIfPresent(FileConfigDO::getStorage, queryVO.getStorage())
                .betweenIfPresent(FileConfigDO::getCreateTime, queryVO.getCreateTime())
        );
    }

    @Override
    public void testFileConfigConnect(Long id) {
        FileConfigDO config = validateFileConfigExists(id);

        FileClient client = fileClientFactory.createFileClient(
                config.getId(),
                config.getStorage(),
                config.getConfig()
        );
        // 测试文件路径
        String testPath = StrUtil.format("/fileConfigTest/connect-test-{}.txt", IdUtil.fastSimpleUUID());

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateTimePatternConstants.ISO_DATE_TIME);
        LocalDateTime.now().format(formatter);
        String testContent = LocalDateTime.now().format(formatter);
        try {
            client.upload(testContent.getBytes(), testPath, null);
            client.delete(testPath);
        } catch (Exception ex) {
            throw new BusinessException(FILE_CONFIG_CONNECTION_ERROR);
        }

    }


    /**
     * 校验文件配置基础信息
     *
     * @param id      配置Id
     * @param name    配置名称
     * @param storage 存储类型
     */
    private void validateFileConfigBasicInfo(Long id, String name, Integer storage) {
        FileConfigDO fileConfig;
        if (StrUtil.isNotBlank(name)) {
            fileConfig = this.baseMapper.selectByName(name);
            if (fileConfig != null && !fileConfig.getId().equals(id)) {
                throw new BusinessException(FILE_CONFIG_NAME_EXISTS);
            }
        }
        if (storage != null) {
            FileStorageEnum storageEnum = FileStorageEnum.getByStorage(storage);
            if (storageEnum == null) {
                throw new BusinessException(FILE_STORAGE_NOT_EXISTS);
            }
        }
    }

    @Override
    public FileConfigDO validateFileConfigExists(Long id) {
        FileConfigDO fileConfig = this.baseMapper.selectById(id);
        if (fileConfig == null) {
            throw new BusinessException(FILE_CONFIG_NOT_EXISTS);
        }
        return fileConfig;
    }

}
